﻿using CheatMenu.Managers;
using CheatMenu.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Logger = BepInEx.Logger;
using BepInEx.Logging;

namespace CheatMenu.Menus
{
    public class MenuButtonList : MenuBase
    {
        private GUIStyle defaultFontControlHeightButtonStyle;
        private GUIStyle defaultFontLabelHeaderStyle;
        private GUIStyle stretchHeightBoxStyle;
        private GUIStyle stretchWidthHeightBoxStyle;
        private GUIStyle commandButtonStyle;
        private GUIStyle labelHeaderStyle;

        private Vector2 commandsStateViewVector;

        protected readonly List<CommandGroup> CommandGroups = new List<CommandGroup>();

        public string HeaderText { get; set; }
        public bool CanClose { get; set; } = true;

        public void ResetScrollVector() => commandsStateViewVector = new Vector2();

        public MenuButtonList(string name, string text = null) : base(name, text) { }

        protected override Vector2 InitializeSize()
        => new Vector2((GUIManager.ControlHeight * 8f) + (GUIManager.PaddingSize * 2) + GUIManager.ScrollBarWidth, (GUIManager.ControlHeight * 12) + (GUIManager.PaddingSize * 2));

        protected override void InitializeGUI()
        {
            defaultFontControlHeightButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fontSize = GUIManager.ControlFontSize,
                fixedHeight = GUIManager.ControlHeight
            };

            defaultFontLabelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                fontStyle = FontStyle.Bold,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };

            stretchHeightBoxStyle = new GUIStyle(GUI.skin.box)
            {
                stretchHeight = true
            };

            stretchWidthHeightBoxStyle = new GUIStyle(GUI.skin.box)
            {
                stretchWidth = true,
                stretchHeight = true
            };

            commandButtonStyle = new GUIStyle(GUI.skin.button)
            {
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontSize = GUIManager.ControlFontSize,
                fixedHeight = GUIManager.ControlHeight
            };

            labelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontStyle = FontStyle.Bold,
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };
        }

        protected override void MenuWindow(int id)
        {
            GUILayout.BeginVertical();
            {
                GUILayout.BeginHorizontal();
                {
                    if (!string.IsNullOrEmpty(HeaderText))
                    {
                        GUILayout.BeginVertical(GUI.skin.box);
                        {
                            GUILayout.Label(HeaderText, defaultFontLabelHeaderStyle);
                        }
                        GUILayout.EndVertical();
                    }
                    GUILayout.FlexibleSpace();
                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        bool guiEnabled = GUI.enabled;
                        GUI.enabled = CanClose && guiEnabled;
                        if (GUILayout.Button("Close", defaultFontControlHeightButtonStyle))
                        {
                            Shown = false;
                        }
                        GUI.enabled = guiEnabled;
                    }
                    GUILayout.EndHorizontal();
                }
                GUILayout.EndHorizontal();

                GUILayout.BeginVertical(stretchHeightBoxStyle);
                {
                    commandsStateViewVector = GUILayout.BeginScrollView(commandsStateViewVector, false, false, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, stretchWidthHeightBoxStyle);
                    for (int i = 0; i < CommandGroups.Count; i++)
                    {
                        CommandGroup group = CommandGroups[i];
                        GUILayout.BeginVertical(GUI.skin.box);
                        {
                            GUILayout.Label(group.Name, labelHeaderStyle);
                            Color oldBackground = GUI.backgroundColor;
                            for (int j = 0; j < group.Commands.Count; j++)
                            {
                                Command command = group.Commands[j];
                                {
                                    if (command.ToggleState)
                                        GUI.backgroundColor = GUIManager.SelectedButtonColor;
                                    else
                                        GUI.backgroundColor = oldBackground;

                                    if (GUILayout.Button(command.Name, commandButtonStyle))
                                        command.InvokeCommand();
                                }
                            }
                            GUI.backgroundColor = oldBackground;
                        }
                        GUILayout.EndVertical();
                    }
                    GUILayout.EndScrollView();


                    //Hacky workaround for the ScrollView not taking mouse scrollwheel focus
                    if (GUIUtil.MouseScrollingAndContained(WindowRect))
                        Input.ResetInputAxes();
                }
                GUILayout.EndVertical();
            }
            GUILayout.EndVertical();
        }

        public void ClearCommandGroups()
        {
            CommandGroups.Clear();
        }

        public void AddCommandGroup(CommandGroup group)
        {
            if (CommandGroups.Where((c) => c.Name.Equals(group.Name, StringComparison.OrdinalIgnoreCase)).Count() == 0)
                CommandGroups.Add(group);
            else
                Logger.Log(LogLevel.Warning, $"Trying to add existing commandgroup with name: {group.Name}");
        }

        public void RemoveCommandGroup(CommandGroup group)
        {
            if (CommandGroups.Contains(group))
                CommandGroups.Remove(group);
            else
                Logger.Log(LogLevel.Warning, $"Trying to remove non-existing commandgroup with name: {group.Name}");
        }
    }
}
